package com.vaadin.pekka.treegridwidget.client.ui;

import java.util.Arrays;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Grid;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;

/**
 * Client side widget which communicates with the server. Messages from the
 * server are shown as HTML and mouse clicks are sent to the server.
 */
public class VTreeGrid extends Composite implements Paintable, ClickHandler {

    /** Set the CSS class name to allow styling. */
    public static final String CLASSNAME = "v-treegrid";

    public static final String CLICK_EVENT_IDENTIFIER = "click";

    /** The client side widget identifier */
    protected String paintableId;

    /** Reference to the server connection object. */
    protected ApplicationConnection client;

    private Grid grid;

    private TreeGridElementBuilder builder;

    private TreeGridData state;

    public VTreeGrid() {
        grid = new Grid(2, 2);
        grid.setCellSpacing(0);
        grid.setHeight("100%");
        grid.setWidth("100%");

        initWidget(grid);

        // This method call of the Paintable interface sets the component
        // style name in DOM tree
        setStyleName(CLASSNAME);

        // Tell GWT we are interested in receiving click events
        sinkEvents(Event.ONCLICK);
        // Add a handler for the click events (this is similar to
        // FocusWidget.addClickHandler())
        addDomHandler(this, ClickEvent.getType());

        builder = new TreeGridElementBuilder();
        state = new TreeGridData();
    }

    /**
     * Called whenever an update is received from the server
     */
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
        // This call should be made first.
        // It handles sizes, captions, tooltips, etc. automatically.
        if (client.updateComponent(this, uidl, true)) {
            // If client.updateComponent returns true there has been no changes
            // and we
            // do not need to update anything.
            return;
        }

        // Save reference to server connection object to be able to send
        // user interaction later
        this.client = client;

        // Save the client side identifier (paintable id) for the widget
        paintableId = uidl.getId();

        // Process attributes/variables from the server
        // The attribute names are the same as we used in
        // paintContent on the server-side
        int updateMode = -1;
        if (uidl.hasAttribute("updatemode")) {
            updateMode = uidl.getIntAttribute("updatemode");
        }
        if (updateMode == 0) {
            insertHeaders(uidl);
            insertData(uidl);
        }
    }

    private void insertData(UIDL uidl) {

    }

    private void insertHeaders(UIDL uidl) {
        final int columnLevels = uidl.getIntAttribute("columnlevels");
        String[][] chs = new String[columnLevels][];
        for (int i = 0; i < columnLevels; i++) {
            chs[i] = uidl.getStringArrayAttribute("ch" + i);
        }
        final int rowLevels = uidl.getIntAttribute("rowlevels");
        String[][] rhs = new String[rowLevels][];
        for (int i = 0; i < rowLevels; i++) {
            rhs[i] = uidl.getStringArrayAttribute("rh" + i);
        }
        System.out.println(columnLevels + " Column Headers: ");
        for (String[] s : chs) {
            System.out.print(Arrays.toString(s) + " ");
        }
        System.out.println("\n" + rowLevels + " Row Headers: ");
        for (String[] s : rhs) {
            System.out.print(Arrays.toString(s) + " ");
        }
        // Resize grid
        final int columns = rowLevels - 1 + chs[0].length;
        if (grid.getColumnCount() != columns) {
            grid.resizeColumns(columns);
            System.out.println("Resizing columns " + columns);
        }
        final int rows = columnLevels - 1 + rhs[0].length;
        if (grid.getRowCount() != rows) {
            grid.resizeRows(rows);
            System.out.println("Resizing rows " + rows);
        }

        String old[][] = state.getColumnHeaders();
        int startingColumn = rowLevels - 1;
        // Set the topmost column headers:
        for (int column = 0; column < chs[0].length; column++) {
            // do set the "measure name" if there is only one measure
            String o = null;
            String n = chs[0][column];
            try {
                o = old[0][column];
            } catch (IndexOutOfBoundsException e) {

            } catch (NullPointerException e) {

            }
            if (o == null || !o.equals(n)) {
                grid.clearCell(0, column + startingColumn);
                // Element cell = grid.getCellFormatter().getElement(0,
                // column + startingColumn);
                if (chs.length == 1) {
                    grid.setWidget(0, column + startingColumn,
                            builder.getLowestHeaderLabel(n));
                    // cell.appendChild(builder.getLowestHeaderCell(n));
                    // cell.setInnerHTML(builder.getLowestHeaderCell(n));
                } else if (column == 0) {
                    grid.setWidget(0, column + startingColumn,
                            builder.getHeaderNameLabel(n));
                    // cell.appendChild(builder.getHeaderNameCell(n));
                    // cell.setInnerHTML(builder.getHeaderNameCell(n));
                } else {
                    grid.setWidget(0, column + startingColumn,
                            builder.getHighestHeaderLabel(n));
                    // cell.appendChild(builder.getHighestHeaderCell(n));
                    // cell.setInnerHTML(builder.getHighestHeaderCell(n));
                }
            }
        }

        // Set the other column headers:
        for (int row = 1; row < chs.length; row++) {
            String[] n = chs[row];
            String[] o;
            o = null;
            try {
                o = old[row];
            } catch (IndexOutOfBoundsException e) {

            } catch (NullPointerException e) {

            }
            if (o == null || !o.equals(n)) {
                // first set the header name
                if (row != chs.length - 1) {
                    grid.clearCell(row, startingColumn);
                    grid.setWidget(row, startingColumn,
                            builder.getHeaderNameLabel(n[0]));
                    // Element nameCell =
                    // grid.getCellFormatter().getElement(row,
                    // startingColumn);
                    // nameCell.appendChild(builder.getHeaderNameCell(chs[row][0]));
                }

                for (int column = 1; column < chs[0].length; column++) {
                    grid.clearCell(row, column + startingColumn);
                    // Element cell = grid.getCellFormatter().getElement(row,
                    // column + startingColumn);
                    int repeat = (row == 1 ? 1 : grid
                            .getWidget(row - 1, column + startingColumn)
                            .getElement().getElementsByTagName("div")
                            .getLength());
                    if (row == chs.length - 1) {
                        grid.setWidget(row, column + startingColumn,
                                builder.buildLowestHeaderCell(n, repeat));
                        // builder.buildLowestHeaderCell(n, repeat, cell);
                        // cell.setInnerHTML(builder
                        // .getLowestHeaderCell(n, repeat));
                    } else {
                        grid.setWidget(row, column + startingColumn,
                                builder.buildColumnHeaderCell(n, repeat));
                        // builder.buildHeaderCell(n, repeat, cell);
                        // cell.setInnerHTML(builder.getHeaderCell(n, repeat));
                    }
                }
            }
        }
        state.setColumnHeaders(chs);
        old = state.getRowHeaders();
        startingColumn = columnLevels - 1;
        // Set the topmost row headers:
        for (int row = 0; row < rhs[0].length; row++) {
            String o = null;
            String n = rhs[0][row];
            try {
                o = old[0][row];
            } catch (IndexOutOfBoundsException e) {

            } catch (NullPointerException e) {

            }
            if (o == null || !o.equals(n)) {
                grid.clearCell(row + startingColumn, 0);
                // Element cell = grid.getCellFormatter().getElement(
                // row + startingColumn, 0);
                if (row == 0) {
                    grid.setWidget(row + startingColumn, 0,
                            builder.getHeaderNameLabel(n));
                    // cell.appendChild(builder.getHeaderNameCell(n));
                    // cell.setInnerHTML(builder.getHighestHeaderCell(n));
                } else {
                    grid.setWidget(row + startingColumn, 0,
                            builder.getHighestHeaderLabel(n));
                    // cell.appendChild(builder.getHighestHeaderCell(n));
                    // cell.setInnerHTML(builder.getHeaderNameCell(n));
                }
            }
        }

        // Set the other row headers:
        for (int column = 1; column < rhs.length; column++) {
            String[] n = rhs[column];
            String[] o;
            o = null;
            try {
                o = old[column];
            } catch (IndexOutOfBoundsException e) {

            } catch (NullPointerException e) {

            }
            if (o == null || !o.equals(n)) {
                // set row header name
                grid.clearCell(startingColumn, column);
                grid.setWidget(startingColumn, column,
                        builder.getRowHeaderNameLabel(n[0]));
                // Element nameCell = grid.getCellFormatter().getElement(
                // startingColumn, column);
                // nameCell.appendChild(builder.getHeaderNameCell(n[0]));
                // nameCell.setInnerHTML(builder.getHeaderNameCell(rhs[column][0]));
                for (int row = 1; row < rhs[0].length; row++) {
                    grid.clearCell(row + startingColumn, column);
                    // Element cell = grid.getCellFormatter().getElement(
                    // row + startingColumn, column);
                    int repeat = (column == 1 ? 1 : grid
                            .getWidget(row + startingColumn, column - 1)
                            .getElement().getElementsByTagName("div")
                            .getLength());
                    grid.setWidget(row + startingColumn, column,
                            builder.buildRowHeaderCell(n, repeat));
                    // builder.buildRowHeaderCell(n, repeat, cell);
                    // cell.setInnerHTML(builder.getRowHeaderCell(n, repeat));
                }
            }
        }
        state.setRowHeaders(rhs);
    }

    /**
     * Called when a native click event is fired.
     * 
     * @param event
     *            the {@link ClickEvent} that was fired
     */
    public void onClick(ClickEvent event) {
        // Send a variable change to the server side component so it knows the
        // widget has been clicked
        String button = "left click";
        // The last parameter (immediate) tells that the update should be sent
        // to the server
        // right away
        client.updateVariable(paintableId, CLICK_EVENT_IDENTIFIER, button, true);
    }
}
